package cn.gjculture.shopping.api.service;

import cn.gjculture.shopping.api.entity.UnifyParam;
import cn.gjculture.shopping.api.entity.*;
import cn.gjculture.shopping.api.util.CFCARAUtil;
import cn.gjculture.shopping.api.util.DateUtils;
import cn.gjculture.shopping.api.util.HttpClient;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class InterfaceService {
    @Value("${pay.sellerNo}")
    private String sellerNo;
    @Value("${pay.returnUrl}")
    private String returnUrl;
    @Value("${pay.notifyUrl}")
    private String notifyUrl;
    @Value("${pay.pfxPath}")
    private String pfxPath;
    @Value("${pay.cerPath}")
    private String cerPath;
    @Value("${pay.pfxPassword}")
    private String pfxPassword;
    @Value("${register.returnUrl}")
    private String registerReturnUrl;
    @Value("${refund.returnUrl}")
    private String refundReturnUrl;
    private String apiVersion = "1.1";
    private String signType = "CFCA";

    @Autowired
    MerchantService merchantService;

    @Autowired
    PayService payService;


    /**
     * 获取调用册商户接口参数
     *
     * @param mer
     * @return
     */
    public InterfaceParam getRegisterParam(Merchant mer) {
        Map<String, Object> resultMap = new LinkedHashMap<>();
        resultMap.put("type", "web");
        resultMap.put("returnUrl", registerReturnUrl);
        resultMap.put("seraialNumber", mer.getMerchantId());
        resultMap.put("merType", mer.getMerType());
        resultMap.put("legalPersonName",mer.getName());
        resultMap.put("legalPersonPhone",mer.getPhone());
        resultMap.put("typeOfID","0");
        resultMap.put("legalPersonIdnum",mer.getIdCardNo());
        InterfaceParam param = this.getParam(resultMap, notifyUrl);
        param.setActionUrl("https://qyfapi.95epay.com/api/api/page/registerPage");
        return param;
    }

    /**
     * 获取调用支付接口参数
     *
     * @param order
     * @param routings
     * @return
     */
    public InterfaceParam getPayParam(Order order, List<RoutingRule.Routing> routings) {
        Map<String, Object> resultMap = new LinkedHashMap<>();
        resultMap.put("sellerNo", sellerNo);
        resultMap.put("payChannels", "{\"fastpay\":false,\"weChatPay\":true,\"weChatPayMobile\":true,\"aliPay\":true,\"aliPayMobile\":true,\"balancePay\":false}");
        resultMap.put("payAmount", order.getOrderTotalSum());
        resultMap.put("apiPayType", "1");//1-即时支付,2-担保支付,3-预授权支付
        resultMap.put("tradeType", "0");//1—充值，0—收款
        resultMap.put("merMerOrderNo", order.getOrderId());
        resultMap.put("orderSubject", order.getOrderSubject());
        if (routings != null) {
            List<JSONObject> list = new ArrayList<>();
            for (RoutingRule.Routing route : routings) {
                JSONObject o = new JSONObject();
                o.put("routingMerNo", route.getMerNo());
                o.put("routingFee", route.getValue().setScale(2, BigDecimal.ROUND_DOWN).toString());
                list.add(o);
            }
            String routingList = JSON.toJSONString(list);
            log.info("routingList:{}", routingList);
            resultMap.put("tempRoutingList", routingList);
        }
        resultMap.put("returnUrl", returnUrl);
        InterfaceParam param = this.getParam(resultMap, notifyUrl);
        param.setActionUrl("http://qyfapi.95epay.com/api/api/hPay/toPayHtml");
        return param;
    }

    public MultiValueMap<String, String> getRefundParam(Pay pay) {
        Map<String, Object> resultMap = new LinkedHashMap<>();
        resultMap.put("sellerNo", sellerNo);
        resultMap.put("Merno", pay.getSwiftNumber().toString());
        resultMap.put("Orderno", pay.getThirdSwiftNumber());
        resultMap.put("payAmount", pay.getAmount());
        resultMap.put("MerRefundNo", pay.getPayId());
        return this.getHttpParams(resultMap);
    }

    /**
     * 拼装公共请求参数
     *
     * @param resultMap
     * @param noteUrl
     * @return
     */
    private InterfaceParam getParam(Map<String, Object> resultMap, String noteUrl) {
        Map<String, Object> requestMap = new LinkedHashMap<>();
        requestMap.put("merNo", sellerNo);
        requestMap.put("version", apiVersion);
        requestMap.put("notifyUrl", noteUrl);
        String timestamp = DateUtils.getDateTime();
        requestMap.put("timestamp", timestamp);
        requestMap.put("apiContent", JSON.toJSONString(resultMap));
        requestMap.put("signType", signType);
        String beforeSignedData = CFCARAUtil.joinMapValue(requestMap, '&');
        log.info("签名前数据集:{}", beforeSignedData);
        String sign = "";
        try {
            sign = CFCARAUtil.signMessageByP1(beforeSignedData, pfxPath, pfxPassword);
        } catch (Exception e2) {
            e2.printStackTrace();
        }
        InterfaceParam param = new InterfaceParam();
        param.setMerNo(sellerNo);
        param.setSignType(signType);
        param.setVersion(apiVersion);
        param.setNotifyUrl(noteUrl);
        param.setSign(sign);
        log.info("sign:{}", sign);
        param.setTimestamp(timestamp);
        log.info("timestamp:{}", timestamp);
        String apiContent = JSON.toJSONString(resultMap);
        param.setApiContent(apiContent);
        log.info("apiContent:{}", apiContent);
        return param;
    }


    public int refund(Pay pay) {
        String url = "https://qyfapi.95epay.com/api/api/refund/apply";
        MultiValueMap<String, String> params = this.getRefundParam(pay);
        String response = HttpClient.client(url, HttpMethod.POST, params);
        log.info("response:{}", response);
        return 1;
    }


    public boolean thirdBack(String code, String msg, String responseType, String responseParameters, String sign) throws Exception {
        log.info("code:{}", code);
        log.info("msg:{}", msg);
        log.info("responseType:{}", responseType);
        log.info("responseParameters:{}", responseParameters);
        log.info("sign:{}", sign);
        String beforeSignedData = this.joinParam(code, msg, responseType, responseParameters);
        //验证签名
        if (CFCARAUtil.verifyMessageByP1(beforeSignedData,sign,cerPath)) {
            log.info("支付异步回调验证签名通过");
            JSONObject responseParam = JSONObject.parseObject(responseParameters);
            switch (responseType) {
                case "1":
                    this.payBack(code, msg, responseParam);
                    break;
                case "2":
                    this.refundBack(code, msg, responseParam);
                    break;
                case "13":
                    this.registerBack(code, msg, responseParam);
                    break;
                default:
                    break;
            }
        } else {
            log.error("支付异步回调验证签名失败");
        }
        return false;
    }


    /**
     * 注册商户回调处理
     *
     * @param code
     * @param msg
     * @param responseParam
     */
    private void registerBack(String code, String msg, JSONObject responseParam) {
        merchantService.back(code, msg, responseParam);
    }

    /**
     * 退款回调处理
     *
     * @param code
     * @param msg
     * @param responseParam
     */
    private void refundBack(String code, String msg, JSONObject responseParam) {
        payService.refundBack(code,msg,responseParam);

    }

    /**
     * 付款回调处理
     *
     * @param code
     * @param msg
     * @param responseParam
     */
    private void payBack(String code, String msg, JSONObject responseParam) {
        payService.payBack(code, msg, responseParam);

    }

    private String joinParam(String code, String msg, String responseType, String responseParameters) {
        Map<String, Object> requestMap = new LinkedHashMap();
        requestMap.put("code", code);
        requestMap.put("msg", msg);
        if(responseType!=null){
            requestMap.put("responseType",responseType);
        }
        requestMap.put("responseParameters", responseParameters);
        String beforeData = CFCARAUtil.joinMapValue(requestMap, '&');
        log.info("签名前数据集:{}", beforeData);
        return beforeData;
    }

    public String unifyPay(UnifyParam unifyParam) {
        String url = "https://qyfapi.95epay.com/api/api/pay/toPay";
        MultiValueMap<String, String> params = this.getUnifyPayParam(unifyParam);
        String response = HttpClient.client(url, HttpMethod.POST, params);
        log.info("response:{}", response);
        JSONObject jsonObject = JSONObject.parseObject(response);
        if ("88".equals(jsonObject.getString("code"))) {
            if ("aliPay".equals(unifyParam.getPayChannel())) {
                return jsonObject.getJSONObject("responseParameters").getString("qrCode");
            } else if ("weChatPay".equals(unifyParam.getPayChannel())) {
                String weChatJson = jsonObject.getJSONObject("responseParameters").getString("payUrlSAO");
                log.info("wxJson:{}", weChatJson);
                return weChatJson;
            }
        }
        return "";
    }

    private MultiValueMap<String, String> getUnifyPayParam(UnifyParam unifyParam) {
        Map<String, Object> resultMap = new LinkedHashMap<>();
        resultMap.put("sellerNo", unifyParam.getMerchantNo());
        resultMap.put("payChannels", unifyParam.getPayChannel());
        resultMap.put("payAmount", unifyParam.getPayAmount());
        resultMap.put("apiPayType", "1");
        resultMap.put("tradeType", "0");
        resultMap.put("merMerOrderNo", unifyParam.getOrderId());
        resultMap.put("orderSubject", unifyParam.getOrderSubject());
        resultMap.put("openId", unifyParam.getOpenid());
        return this.getHttpParams(resultMap);
    }

    public boolean verifySign(String code, String msg, String responseParameters, String sign) throws Exception {
        String beforeSignedData = this.joinParam(code, msg, null, responseParameters);
        return CFCARAUtil.verifyMessageByP1(beforeSignedData, sign, cerPath);
    }

    public boolean transfer(Pay pay, Merchant merchant) {
        String url="https://qyfapi.95epay.com/api/api/platformTransfer/toAcc";
        MultiValueMap<String, String> params= getTransferParam(pay,merchant);
        String response = HttpClient.client(url, HttpMethod.POST, params);
        log.info("response:{}", response);
        JSONObject jsonObject = JSONObject.parseObject(response);
        if ("88".equals(jsonObject.getString("code"))) {
            return true;
        }
        return false;
    }

    private MultiValueMap<String, String> getTransferParam(Pay pay, Merchant merchant) {
        Map<String, Object> resultMap = new LinkedHashMap<>();
        resultMap.put("payeeNo", merchant.getSonMerNo());
        resultMap.put("payeeName", merchant.getName());
        resultMap.put("amount", pay.getAmount());
     //   resultMap.put("cardNo", merchant.getBankCardNo());
        return getHttpParams(resultMap);
    }

    private MultiValueMap<String, String> getHttpParams(Map<String, Object> resultMap) {
        InterfaceParam interfaceParam = getParam(resultMap, notifyUrl);
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("merNo", interfaceParam.getMerNo());
        params.add("signType", interfaceParam.getSignType());
        params.add("version", interfaceParam.getVersion());
        params.add("notifyUrl", interfaceParam.getNotifyUrl());
        params.add("sign", interfaceParam.getSign());
        params.add("timestamp", interfaceParam.getTimestamp());
        params.add("apiContent", interfaceParam.getApiContent());
        return params;
    }
}
